import socket
import struct
'''ending'''
import os
import signal
import multiprocessing as mp
import time


class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class Server(object, metaclass=Singleton):
    def __init__(self, port: int = 8000):
        self.address = ('', port)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.address)
        self.socket.listen(32)  # 接受连接数量？
        ## added
        self.work_process_list: list[mp.Process] = []

    def _threadfunc(self, sock: socket.socket, addr):
        """
        根据接收到的第一句话判断客户端身份
        并交给不同的处理函数(检查空调系统状态, 不对则拒绝)
        顾客 前台 经理 管理 0-3
        """
        data = sock.recv(1024)
        data = struct.unpack('!iii', data)
        print(addr, data)
        data = str(data[0] + data[1] + data[2])
        sock.send(data.encode())
        while True:
            data = sock.recv(1024)
            if data:
               print(addr, data.decode())
               if int(data.decode()) == 225:
                   self.shutdown()
               data = str(int(data.decode()) + 1)
               sock.send(data.encode())
            else:
               print('client dosconnect!')
               sock.close()
               break


    def recv_file(sock: socket.socket):
        fileinfo_size = struct.calcsize('!128sl')
        buf = sock.recv(fileinfo_size)

        if buf:
            filename, filesize = struct.unpack('!128sl', buf)
            fn = filename.strip(b'\00').decode('utf-8')
            print('file new name is {0}, filesize if {1}'.format(str(fn), filesize))

            recvd_size = 0
            file_path = r'recv_file/' + str(fn)
            fp = open(file_path, 'wb')
            print('start receiving...')
            while not recvd_size == filesize:
                if filesize - recvd_size > 1024:
                    data = sock.recv(1024)
                    recvd_size += len(data)
                else:
                    data = sock.recv(filesize - recvd_size)
                    recvd_size = filesize
                fp.write(data)
            fp.close()
            print('end receive...')
            return file_path
        else:
            return False

    def run_func(self):
        while True:
            conn, addr = self.socket.accept()
            t = mp.Process(target=self._threadfunc, args=(conn, addr))
            self.work_process_list.append(t)
            t.start()

    def run(self):
        signal.signal(signal.SIGCLD, signal.SIG_IGN)
        p = mp.Process(target=self.run_func, args=())
        # self.work_process_list.append(p)
        p.start()

    def shutdown(self):
        """
        关不掉啊。。
        """
        self.socket.close()

        print(self.work_process_list)
        for p in self.work_process_list:
            if p.is_alive():
                p.terminate()

# ~/Course_code/se_proj/src/backend/tcptest

if __name__ == '__main__':
    serv = Server(port = 8000)
    serv.run()
    print('start server')
    serv.shutdown()
    

'''
def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) 
    if res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread: mp.Process):
    _async_raise(thread.ident, SystemExit)
'''
